﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using System.Linq.Dynamic;
using HelloWorld.Code.DataAccess.Paging;

namespace HelloWorld.Code.DataAccess
{
    /// <summary>
    /// Base repository class
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Repository<T> : IRepository<T> where T : class
    {
        internal MvcDemoEntities Context;
        internal Repository(MvcDemoEntities context)
        {
            Context = context;
        }

        /// <summary>
        /// Return a paged list.
        /// </summary>
        /// <param name="filters">A lambda expression used to filter the result.</param>
        /// <param name="sorting">The sort expression, example: ColumnName desc</param>
        /// <param name="includeList">The list of related entities to load.</param>
        /// <param name="currentPageNumber">The page number to return.</param>
        /// <param name="pageSize">The page size (the maximum number of elements to return in the list).</param>
        /// <returns></returns>
        public IPagedList<T> Search(Expression<Func<T, bool>> filters, string sorting, List<string> includeList, int currentPageNumber, int pageSize)
        {
            using (var context = new MvcDemoEntities())
            {
                return GetQuery(context, filters, sorting, includeList).ToPagedList(currentPageNumber, pageSize);
            }
        }

        /// <summary>
        /// Return a list.
        /// </summary>
        /// <param name="filters">A lambda expression used to filter the result.</param>
        /// <param name="sorting">The sort expression, example: ColumnName desc</param>
        /// <param name="includeList">The list of related entities to load.</param>
        /// <returns></returns>
        public IList<T> Search(Expression<Func<T, bool>> filters, string sorting, List<string> includeList)
        {
            using (var context = new MvcDemoEntities())
            {
                return GetQuery(context, filters, sorting, includeList).ToList();
            }
        }

        /// <summary>
        /// Method used to build the query that will reflect the filter conditions and the sort expression.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="filters"></param>
        /// <param name="sorting"></param>
        /// <param name="includeList"></param>
        /// <returns></returns>
        protected IQueryable<T> GetQuery(ObjectContext context, Expression<Func<T, bool>> filters, string sorting, List<string> includeList)
        {
            var objectSet = context.CreateObjectSet<T>();
            if (string.IsNullOrEmpty(sorting))
                sorting = objectSet.EntitySet.ElementType.KeyMembers.First().Name; //consider the PK as the default sort column

            var objectQuery = (ObjectQuery<T>)objectSet;
            if (includeList != null)
            {
                foreach (var include in includeList)
                {
                    objectQuery = objectQuery.Include(include);
                }
            }

            var query = objectQuery.Where(filters == null ? t => 1 == 1 : filters);
            query = query.OrderBy(sorting);
            return query;
        }
    }
}